﻿using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Collections.Specialized;
using Com.Toook.Common;
using Com.Toook.ParseHtml;
using NSoup.Select;
using System.Collections.Generic;
using System.Text;
using Rule = Com.Toook.ParseHtml.Entity.Rule;
using Com.Toook.ParseHtml.Entity;
using NSoup.Nodes;

/// <summary>
///GetContentNextPage 根据“下一页”链接，一个接一个地获取内容
/// </summary>
public class GetContentNextPage
{
    public GetContentNextPage(DetailRoadMap roadMap)
    {
        this.roadMap = roadMap;
    }
    private NSoup.Nodes.Document doc = null;
    /// <summary>
    /// 详细内容的解析规则
    /// </summary>
    private DetailRoadMap roadMap;
    /// <summary>
    /// 保存从跳转页面获取的字段名、值
    /// </summary>
    private StringDictionary dicResult = new StringDictionary();
    /// <summary>
    /// 保存内容，有分页的拼接分页内容
    /// </summary>
    private StringBuilder sbFinalContent = new StringBuilder(512);
    /// <summary>
    /// 保存页面的初始根元素
    /// </summary>
    private Elements rootElements = new Elements();

    /// <summary>
    /// 特殊位置获取下一页url. 下一页是第二个elements.如52duzhe.com
    /// </summary>
    public int lastNextIndex = 0;
    public string prevUrl = "";
    public bool IsFirstGetContent = true;
    /// <summary>
    /// 获取并保存currentUrl的内容；同时获取下一页url，继续。
    /// </summary>
    /// <param name="currentUrl"></param>
    public void GetContent(string currentUrl)
    {
        //添加其他字段值到结果字典
        dicResult.Clear();        

        //2、最后从内容页面获取内容
        InitRootElements(currentUrl, roadMap.contentPage.InitStep);
        
        if (this.rootElements.Count == 0)//没有获取到初始节点，即此网页不满足配置文件的解析规则
        {
            LogHelper.Log.Error("GetContent(" + currentUrl + ")中InitRootElements()没有获取到初始节点.顺序获取结束。");
            return;
        }
        else
        {
            //解析出内容
           ParseStepByStep(this.rootElements, roadMap.contentPage.rule);
           if (this.dicResult.Count == 0)
           {
               LogHelper.Log.Error("ParseStepByStep时没有获取到内容节点. url=" + currentUrl);
           }
           else
           {
               //解析完内容后，保存到数据库
               if (IsFirstGetContent)
               {
                   IsFirstGetContent = false;
                   if (!SaveResultToAccess.HaveSameArticle(currentUrl, roadMap.InsertTableName))
                   {
                       SaveResultToAccess.SaveNextPageArticleContent(currentUrl, roadMap.InsertTableName, dicResult);
                   }
               }
               else
               {
                   SaveResultToAccess.SaveNextPageArticleContent(currentUrl, roadMap.InsertTableName, dicResult);
               }
           }
        }        

        string nextPage = GetNextPageUrl();
        //继续获取下一页内容
        if (!string.IsNullOrEmpty(nextPage) && prevUrl != nextPage && !SaveResultToAccess.HaveSameArticle(nextPage, roadMap.InsertTableName))
        {
            prevUrl = currentUrl;
            GetContent(nextPage);
        }
    }
    /// <summary>
    /// 获取并保存orderUrl的内容。
    /// </summary>
    /// <param name="currentUrl"></param>
    public bool GetContentOrder(string orderUrl)
    {
        bool isSuccess = false;
        //添加其他字段值到结果字典
        dicResult.Clear();

        //2、最后从内容页面获取内容
        InitRootElements(orderUrl, roadMap.contentPage.InitStep);

        if (this.rootElements.Count == 0)//没有获取到初始节点，即此网页不满足配置文件的解析规则
        {
            LogHelper.Log.Error("GetContent(" + orderUrl + ")中InitRootElements()没有获取到初始节点.顺序获取结束。");
            isSuccess = false;
        }
        else
        {
            //解析出内容
            ParseStepByStep(this.rootElements, roadMap.contentPage.rule);
            if (this.dicResult.Count == 0)
            {
                LogHelper.Log.Error("ParseStepByStep时没有获取到内容节点. url=" + orderUrl);
                isSuccess = false;
            }
            else
            {               
                if (!SaveResultToAccess.HaveSameArticle(orderUrl, roadMap.InsertTableName))
                {
                    SaveResultToAccess.SaveNextPageArticleContent(orderUrl, roadMap.InsertTableName, dicResult);
                }
                isSuccess = true;
            }
        }
        return isSuccess;
    }
    /// <summary>
    /// 获取下一页Url。遍历PageRuleList，用每个可能的规则获取下一页url
    /// </summary>
    /// <returns></returns>
    private string GetNextPageUrl()
    {
        string nextPageUrl = null;
        foreach (PageRule pageRule in roadMap.contentPage.PageRuleList)
        {
            nextPageUrl = GetNextPageUrlString(this.rootElements, pageRule.NextPageRule);
            if (!string.IsNullOrEmpty(nextPageUrl))
            {
                break;//获取到下一页地址后就退出
            }
        }
        return nextPageUrl;
    }
    
    /// <summary>
    /// 获取下一页Url地址
    /// </summary>
    /// <param name="initElements"></param>
    /// <param name="rule"></param>
    /// <returns></returns>
    private string GetNextPageUrlString(Elements initElements, Rule rule)
    {
        string nextPageUrl = null;
        //1、根据rule、step获取包含下一页链接的元素
        initElements = ParseElements.GetElementsByStep(initElements, rule);

        //2、根据Property获取下一页Url
        if (initElements.Count > 0 && rule.NextProperty())
        {
            while (rule.CurrentProperty.NextStep())//属性中还有需要处理的步骤
            {
                Step step = rule.CurrentProperty.CurrentStep;
                initElements = ParseElements.GetAndMergeElements(initElements, step);
                if (initElements.Count == 0)
                {
                    break;
                }                
            }
            rule.CurrentProperty.ResetNextStep();
            if (initElements.Count > 0)
            {
                if (lastNextIndex == 2 && initElements.Count == 2)
                {
                    Elements eles = new Elements();
                    eles.Add(initElements[1]);
                    initElements = eles;
                }
                //获取下一页Url
                nextPageUrl = ParseElements.GetResultStringByResult(initElements, rule.CurrentProperty.Result);
            }
        }
        rule.ResetNextProperty();

        return nextPageUrl;
    }
    /// <summary>
    /// 设置页面初始根元素
    /// </summary>
    /// <param name="url"></param>
    /// <param name="step"></param>
    private void InitRootElements(string url, Step step)
    {
        this.rootElements = GetInitRootElements(url, step);
    }
    /// <summary>
    /// 根据分类页面URL和初始步骤，获取第一层 initElements 元素
    /// </summary>
    /// <param name="sourceUrl">分类页面URL</param>
    /// <param name="initStep">初始步骤</param>
    /// <returns></returns>
    private Elements GetInitRootElements(string sourceUrl, Step initStep)
    {
        Elements elements = new Elements();
        try
        {
            //用html字符串解析的doc对象，不能获取 abs:href

            //string html = Utils.DownloadHtml(sourceUrl, null);
            //if (string.IsNullOrEmpty(html))
            //{
            //    return elements;
            //}
            //else
            //{
            //    try
            //    {
            //        doc = NSoup.NSoupClient.Parse(html);
            //    }
            //    catch (Exception pe)
            //    {
            //        LogHelper.Log.Error("解析html错误。NSoup.NSoupClient.Parse(html)。html=" + html, pe);
            //    }
            //}
            doc = NSoup.NSoupClient.Connect(sourceUrl).Get();
        }
        catch (Exception ex)
        {
            LogHelper.Log.Warn("下载网页失败。GetInitRootElements()。sourceUrl=" + sourceUrl, ex);
            return elements;
        }

        Element body = doc.Body;
        elements = ParseElements.GetElements(initStep, body);

        return elements;
    }
    private List<string> ParseStepByStep(Elements initElements, Rule rule)
    {
        List<string> nextTransferPageUrl = new List<string>();
        StringBuilder sb = new StringBuilder();

        //1、按照Rule中的Step规则，解析出符合条件的元素列表。供Property获取最终结果用
        initElements = ParseElements.GetElementsByStep(initElements, rule);
        if (initElements.Count == 0)
        {
            return nextTransferPageUrl;
        }

        //将rule/step解析到的Elements保存到stepElements
        Elements stepElements;
        //跳转页面initElements.Count 一般只有1个结果
        if (initElements.Count == 1)
        {
            stepElements = new Elements();
            stepElements.Add(initElements[0]);//从列表中取一个元素放到stepElements中，然后解析出此元素中包含的每个结果属性

            while (rule.NextProperty())
            {
                while (rule.CurrentProperty.NextStep())//属性中还有需要处理的步骤
                {
                    Step step = rule.CurrentProperty.CurrentStep;
                    stepElements = ParseElements.GetAndMergeElements(stepElements, step);
                    if (stepElements.Count == 0)
                    {
                        break;
                    }
                }
                rule.CurrentProperty.ResetNextStep();

                //获取最终属性结果
                string result = ParseElements.GetResultStringByResult(stepElements, rule.CurrentProperty.Result);
                if (rule.CurrentProperty.PropertyName == "url")
                {
                    nextTransferPageUrl.Add(result);//取得下一页的url
                }
                else if (rule.CurrentProperty.PropertyName.ToLower() == "finalcontent")
                {
                    sbFinalContent.Append(result);//保存最终内容
                }
                else//其他结果属性，添加到结果字典
                {
                    dicResult.Add(rule.CurrentProperty.PropertyName, result);
                }

                //获取一个属性后,stepElements已经只包含一个结果属性，要重新给stepElements赋值为整个结果元素集合
                stepElements = new Elements();
                stepElements.Add(initElements[0]);
            }
            rule.ResetNextProperty();
        }

        return nextTransferPageUrl;
    }
    /// <summary>
    /// 设置dicResult的属性值
    /// </summary>
    /// <param name="row"></param>
    private void InitDicResult(DataRow row)
    {
        dicResult.Clear();

        if (!string.IsNullOrEmpty(roadMap.SqlFields))
        {
            string[] sqlFields = roadMap.SqlFields.Split(',');
            foreach (string field in sqlFields)
            {
                dicResult.Add(field.Trim(), row[field.Trim()].ToString());//要trim()掉配置文件的空格，否则row[" column "]会找不到
            }
        }
    }
}